package playwrightpool

import (
  "context"
  "errors"
  "github.com/cloudwego/hertz/pkg/common/hlog"
  "time"

  "github.com/playwright-community/playwright-go"
)

// Session 封装了一个独立的浏览器会话：一个 Browser 与一个 Page
type Session struct {
  browser playwright.Browser
  page    playwright.Page
}

// newSession 创建一个新的会话（Browser + Page）
// 注意：使用同一个全局 pw 实例，但每个会话独立启动 Browser 和 Page
func newSession(pw *playwright.Playwright) (*Session, error) {
  browser, err := pw.Chromium.Launch()
  if err != nil {
    return nil, err
  }
  page, err := browser.NewPage()
  if err != nil {
    _ = browser.Close()
    return nil, err
  }
  return &Session{
    browser: browser,
    page:    page,
  }, nil
}

// Close 关闭会话中的 Browser（Page 会随 Browser 一同关闭）
func (s *Session) Close() error {
  return s.browser.Close()
}

// Pool 管理多个会话，每个会话包含一个 Browser 和一个 Page
type Pool struct {
  sessions chan *Session
  pw       *playwright.Playwright
}

// NewPool 创建一个新的池，池中包含 poolSize 个独立会话
func NewPool(poolSize int) (*Pool, error) {
  pw, err := playwright.Run()
  if err != nil {
    return nil, err
  }

  p := &Pool{
    sessions: make(chan *Session, poolSize),
    pw:       pw,
  }

  // 创建 poolSize 个独立会话
  for i := 0; i < poolSize; i++ {
    sess, err := newSession(pw)
    if err != nil {
      // 出错时关闭已经创建的会话并停止 pw
      for j := 0; j < i; j++ {
        s := <-p.sessions
        _ = s.Close()
      }
      _ = pw.Stop()
      return nil, err
    }
    p.sessions <- sess
  }
  return p, nil
}

// FetchHTML 使用池中一个会话，跳转到 url 并返回页面 HTML 内容
func (p *Pool) FetchHTML(url string) (string, error) {
  hlog.Info("fetch:{}", url)
  var sess *Session
  select {
  case sess = <-p.sessions:
    // 获取到会话
  case <-time.After(60 * time.Second):
    return "", errors.New("超时：没有可用的浏览器会话")
  }

  // 使用完后归还会话（归还前可选重置页面状态）
  defer func() {
    // 将页面跳转到空白页，防止干扰后续请求
    _, _ = sess.page.Goto("about:blank")
    p.sessions <- sess
  }()

  // 设置超时上下文（例如 60 秒）
  _, cancel := context.WithTimeout(context.Background(), 60*time.Second)
  defer cancel()

  // 跳转到指定 URL
  _, err := sess.page.Goto(url, playwright.PageGotoOptions{
    Timeout:   playwright.Float(60000),
    WaitUntil: playwright.WaitUntilStateNetworkidle,
  })
  if err != nil {
    return "", err
  }

  // 获取页面 HTML 内容
  html, err := sess.page.Content()
  if err != nil {
    return "", err
  }
  return html, nil
}

// Close 释放池中所有资源
func (p *Pool) Close() error {
  // 关闭所有会话
  close(p.sessions)
  for sess := range p.sessions {
    _ = sess.Close()
  }
  // 停止全局 Playwright
  return p.pw.Stop()
}
